﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;

namespace LunoCode.World
{
    public static class com
    {
        public static Random rand = new Random(22);
        public static int rnd(int min, int max)
        {
            return rand.Next(min, max + 1);
        }
        public static int dice()
        {
            return rnd(1, 6);
        }
    }

    public class Unit : WorldObject
    {
        public Unit(World w)
            : base(w)
        {
        }
    }

    public class DuelLunohode : Unit 
    {
        public new DuelWorld World;
        public int Life = 3;
        public bool Block = false;
        public int X;
        public int Energy;

        public DuelLunohode(DuelWorld w, int X)
            : base(w)
        {
            this.X = X;
        }

        public void Hit()
        {
            if (Block)
            {
                Block = false;
                return;
            }
            --Life;
            if (Life < 1) Die();
        }

        public void StartMove()
        {
            Energy = com.dice();
        }

        public void Die()
        {
        }
    }
    
    public class World
    {
    }

    //public class ErrorList
    //{
    //    string[] Errors = new string[7];
    //    int Count = 0;
    //    public string GetLastError()
    //    {
    //        if (Count == 0) return null;
    //        return Errors[Count - 1];
    //    }
    //    public void AddError(string s)
    //    {
    //        ++Count;
    //        Errors[Count - 1] = s;
    //    }
    //    public void Clear()
    //    {
    //        Count = 0;
    //    }

    //}

    //public class WorldMemory
    //{
    //    public ArrayList Notes = new ArrayList();

    //}

    public abstract class MemoryNote
    {
        public abstract void Execute();

        public ArrayList Conditions = new ArrayList();

        public Animation Condition
        {
            get
            {
                if (Conditions.Count == 0) return null;
                return Conditions[Conditions.Count - 1] as Animation;
            }
            set
            {
                Conditions.Add(value);
            }
        }

        public MemoryNote(Animation Condition)
        {
            this.Condition = Condition;
        }

        public bool TryExecute(Animation Animation)
        {
            if (Conditions.IndexOf(Animation) >= 0)
                Conditions.Remove(Animation);
            if (Conditions.Count != 0) return false;
            Execute();
            return true;
        }
    }

    public abstract class WorldObject 
    {
        public World World;
        public WorldObject(World w)
        {
            this.World = w;
        }
    }

    public class DamageMemoryNote : MemoryNote
    {
        DuelLunohode Target;
        int Damage;
        public DamageMemoryNote(Animation Condition, DuelLunohode Target, int Damage)
            : base(Condition)
        {
            this.Target = Target;
            this.Damage = Damage;
        }
        public override void Execute()
        {
            for (int i = 0; i < Damage; i++)
                Target.Hit();
        }
    }


    public class FireMemoryNote : MemoryNote
    {
        DuelLunohode Target;
        public FireMemoryNote(Animation Condition, DuelLunohode Target)
            : base(Condition)
        {
            this.Target = Target;
        }
        public override void Execute()
        {
            Target.World.Animation = new Damaging(Target, 1);
            Target.World.Memory.Add(new DamageMemoryNote(Target.World.Animation, Target, 1));
            foreach (CheckEnergyMemoryNote c in Target.World.Memory)
                c.Condition = Target.World.Animation;
        }
    }

    public class BlockMemoryNote : MemoryNote
    {
        DuelLunohode Maker;
        public BlockMemoryNote(Animation Condition, DuelLunohode Maker)
            : base(Condition)
        {
            this.Maker = Maker;
        }
        public override void Execute()
        {
            Maker.Block = true;
        }
    }
    
    public class CheckEnergyMemoryNote : MemoryNote
    {
        DuelLunohode Maker;
        public CheckEnergyMemoryNote(Animation Condition, DuelLunohode Maker)
            : base(Condition)
        {
            this.Maker = Maker;
        }
        public override void Execute()
        {
            if (Maker.Energy < 1)
                Maker.World.ChangeMove();
        }
    }

    public class SpendEnergyMemoryNote : MemoryNote
    {
        DuelLunohode Maker;
        int Energy;

        public SpendEnergyMemoryNote(Animation Condition, DuelLunohode Maker, int Energy)
            : base(Condition)
        {
            this.Maker = Maker;
            this.Energy = Energy;
        }
        public override void Execute()
        {
            Maker.Energy -= Energy;
        }
    }

    
    public class EndingGameMemoryNote : MemoryNote
    {
        DuelLunohode Winner;
        public EndingGameMemoryNote(Animation Condition, DuelLunohode Winner)
            : base(Condition)
        {
            this.Winner = Winner;
        }
        public override void Execute()
        {
            Winner.World.Playing = false;
            if (Winner != null) Winner.World.Winner = Winner;
        }
    }

    public class MoveMemoryNote : MemoryNote
    {
        DuelLunohode Maker;
        int To;
        public MoveMemoryNote(Animation Condition, DuelLunohode Maker, int To)
            : base(Condition)
        {
            this.Maker = Maker;
            this.To = To;
        }
        public override void Execute()
        {
            Maker.X = To;
        }
    }

    

    public class SkipMemoryNote : MemoryNote
    {
        DuelLunohode Maker;
        public SkipMemoryNote(Animation Condition, DuelLunohode Maker)
            : base(Condition)
        {
            this.Maker = Maker;
        }
        public override void Execute()
        {
            Maker.World.ChangeMove();
        }
    }

    public class SurrenderMemoryNote : MemoryNote
    {
        DuelLunohode Maker;
        public SurrenderMemoryNote(Animation Condition, DuelLunohode Maker)
            : base(Condition)
        {
            this.Maker = Maker;
        }
        public override void Execute()
        {
            
        }
    }

    public class StartMoveMemoryNote : MemoryNote
    {
        DuelLunohode Maker;
        int Energy;
        public StartMoveMemoryNote(Animation Condition, DuelLunohode Maker, int Energy)
            : base(Condition)
        {
            this.Maker = Maker;
            this.Energy = Energy;
        }
        public override void Execute()
        {
            Maker.World.Mover = Maker;
            Maker.Energy = Energy;
        }
    }

    public class DriveMemoryNote : MemoryNote
    {
        DuelLunohode Maker;
        public DriveMemoryNote(Animation Condition, DuelLunohode Maker)
            : base(Condition)
        {
            this.Maker = Maker;
        }
        public override void Execute()
        {
            if (Maker == (Maker.World as DuelWorld).FirstPlayer)
                ++Maker.X;
            else
                --Maker.X;
            Maker.Energy -= 1;
        }
    }

    public class StartMemoryNote : MemoryNote
    {
        DuelLunohode Starter;
        public StartMemoryNote(Animation Condition, DuelLunohode Starter)
            : base(Condition)
        {
            this.Starter = Starter;
        }
        public override void Execute()
        {
            Starter.World.StartMove(Starter);
        }
    }

    public class SuperStrikeMemoryNote : MemoryNote
    {
        DuelLunohode Maker, Target;
        public SuperStrikeMemoryNote(Animation Condition, DuelLunohode Maker, DuelLunohode Target)
            : base(Condition)
        {
            this.Maker = Maker;
            this.Target = Target;
        }
        public override void Execute()
        {
            Maker.Hit();
            for (int i = 0; i < 3; i++)
                Target.Hit();
            Maker.Energy -= 5;
            Maker.World.CheckWin();
        }
    }

    public class Cell : WorldObject
    {
        public int x;
        public Cell(World w, int x)
            : base(w)
        {
            this.x = x;
        }
    }

    public class DuelWorld : World
    {
        public int XLength = 8;
        public DuelLunohode FirstPlayer, SecondPlayer;

        public int Distance
        { get { return SecondPlayer.X - FirstPlayer.X; } }

        string error = null;

        public string Error
        {
            get { string s = error; error = null; return s; }
            set { error = value; }
        }

        public DuelWorld()
        {
            FirstPlayer = new DuelLunohode(this, 0);
            SecondPlayer = new DuelLunohode(this, XLength);
        }

        public bool Playing = false;
        public DuelLunohode Winner = null;

        public ArrayList Animations = new ArrayList();

        public Animation Animation
        {
            get
            {
                if (Animations.Count == 0) return null;
                Animation a = Animations[Animations.Count - 1] as Animation;
                //Animations.Remove(a);
                return a;
            }
            set
            {
                Animations.Add(value);
            }
        }

        public DuelLunohode Mover = null;

        public ArrayList Memory = new ArrayList();

        public DuelLunohode Another(DuelLunohode x)
        {
            if (x == FirstPlayer) return SecondPlayer; else return FirstPlayer;
        }

        public void Refresh(LunAction Action, Animation Animation)
        {
            Animations.Clear();
            switch (Action)
            {
                case LunAction.Fire:
                    {
                        Fire();
                        break;
                    }
                case LunAction.Block:
                    {
                        Block();
                        break;
                    }
                case LunAction.SuperStrike:
                    {
                        SuperStrike();
                        break;
                    }
                case LunAction.SkipMove:
                    {
                        SkipMove();
                        break;
                    }
                case LunAction.Drive:
                    {
                        Drive();
                        break;
                    }
                case LunAction.AnimationEnd:
                    {
                        AnimationEnd(Animation);
                        break;
                    }
                case LunAction.Surrender:
                    {
                        Surrender();
                        break;
                    }
                case LunAction.GameStart:
                    {
                        Start();
                        break;
                    }
            }

        }

        private void Start()
        {
            DuelLunohode Starter;
            if (com.dice() % 2 == 0)
                Starter = FirstPlayer;
            else
                Starter = SecondPlayer;
            Animation = new GameStarting(Starter);
            Memory.Add(new StartMemoryNote(Animation, Starter));
        }

        private void Surrender()
        {
            Animation = new DuelLunohodeSurrendering(Mover);
            Memory.Add(new SurrenderMemoryNote(Animation, Mover));
        }

        private void AnimationEnd(Animation Animation)
        {
            int i = 0;
            while (i < Memory.Count)
            {
                if ((Memory[i] as MemoryNote).TryExecute(Animation))
                    Memory.RemoveAt(i);
                else
                    ++i;
            }
        }

        public void ChangeMove()
        {
            StartMove(Another(Mover));
        }

        public void StartMove(DuelLunohode Maker)
        {
            int Energy = com.dice();
            Animation = new DuelLunohodeStartingMove(Maker, Energy);
            Memory.Add(new StartMoveMemoryNote(Animation, Maker, Energy));
        }

        private void Drive()
        {
            if (Distance < 2)
            {
                Animation = new WorldError(LunError.NoPlaceAhead);
                return;
            }
            int x = Mover.X;
            if (Mover == FirstPlayer) ++x; else --x;
            Animation = new DuelLunohodeDriving(Mover, x);
            Memory.Add(new MoveMemoryNote(Animation, Mover, x));
            CheckEnergyMemoryNote c;
            Memory.Add(c = new CheckEnergyMemoryNote(Animation, Mover));

            Animation = new EnergySpending(Mover, 1);
            c.Condition = Animation;
        }

        private void SkipMove()
        {
            Animation = new DuelLunohodeSkippingMove(Mover);
            Memory.Add(new SkipMemoryNote(Animation, Mover));
        }

        private void SuperStrike()
        {
            if (Mover.Energy < 5)
            {
                Animation = new WorldError(LunError.NotEnoughEnergy);
                return;
            }
            if (Distance > 1)
            {
                Animation = new WorldError(LunError.EnemyTooFar);
                return;
            }
            Animation = new DuelLunohodeSuperStrike(Mover, Another(Mover));
            Memory.Add(new SuperStrikeMemoryNote(Animation, Mover, Another(Mover)));
            CheckEnergyMemoryNote c;
            Memory.Add(c = new CheckEnergyMemoryNote(Animation, Mover));

            Animation = new EnergySpending(Mover, 5);
            c.Condition = Animation;
        }

        private void Block()
        {
            if (Mover == null) return;
            if (Mover.Energy < 2)
            {
                Animation = new WorldError(LunError.NotEnoughEnergy);
                return;
            }
            if (Mover.Block)
            {
                Animation = new WorldError(LunError.AlreadyBlocked);
                return;
            }
            Animation = new DuelLunohodeBlocking(Mover);
            Memory.Add(new BlockMemoryNote(Animation, Mover));
            CheckEnergyMemoryNote c;
            Memory.Add(c = new CheckEnergyMemoryNote(Animation, Mover));

            Animation = new EnergySpending(Mover, 2);
            Memory.Add(new SpendEnergyMemoryNote(Animation, Mover, 2));
            c.Condition = Animation;
        }

        public void Fire()
        {
            if (Mover == null) return;
            if (Mover.Energy < 3)
            {
                Animation = new WorldError(LunError.NotEnoughEnergy);
                return;
            }

            int FireDistance = com.dice();
            if (FireDistance > Distance) FireDistance = Distance;

            int x = Mover.X;
            if (Mover == FirstPlayer) x += FireDistance; else x -= FireDistance;
            Animation = new BulletFlight(Mover.X, x);
            if (FireDistance >= Distance)
                Memory.Add(new FireMemoryNote(Animation, Another(Mover)));

            CheckEnergyMemoryNote c;
            Memory.Add(c = new CheckEnergyMemoryNote(Animation, Mover));

            Animation = new EnergySpending(Mover, 3);
            Memory.Add(new SpendEnergyMemoryNote(Animation, Mover, 3));
            c.Condition = Animation;
        }

        const string NotEnoughEnergyError = "Не хватает энергии";
        const string OtherErrors = "Нельзя так делать!";

        internal void CheckWin()
        {
            if (FirstPlayer.Life >= 1 && SecondPlayer.Life >= 1) return;
            DuelLunohode Winner = null;
            if (FirstPlayer.Life < 1 && SecondPlayer.Life >= 1) Winner = SecondPlayer;
            if (FirstPlayer.Life >= 1 && SecondPlayer.Life < 1) Winner = FirstPlayer;
            Win(Winner);
        }

        private void Win(DuelLunohode Winner)
        {
            Animation = new EndingGame(Winner);
            Memory.Add(new EndingGameMemoryNote(Animation, Winner));
        }
    }
}
